package com.wangjiacai.hqlQuery.util;


import com.wangjiacai.hqlQuery.hql.condition.Condition;
import com.wangjiacai.hqlQuery.hql.logic.Or;
import com.wangjiacai.hqlQuery.hql.ClassName;
import com.wangjiacai.hqlQuery.hql.Ignore;
import com.wangjiacai.hqlQuery.hql.condition.where.Like;
import lombok.Data;
import org.springframework.util.StringUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/*
 * @auther: wangjiacai
 *
 * @create: 2018-08-07 17:18:26
 */
public class HqlUtil {

    private static String getClassName(Object object) {
        Class objectClass = object.getClass();
        Annotation annotation = objectClass.getAnnotation(ClassName.class);
        if (annotation != null) {
            ClassName className = (ClassName) annotation;
            return className.value().getSimpleName();
        } else {
            return object.getClass().getSimpleName();
        }
    }

    private static String getAndHql(Annotation annotation,Condition.Where where, String property, String column,Object obj,Object value) {
        return " and " + where.where(annotation,property, column,obj,value);
    }

    private static String getOrHql(Annotation annotation,Condition.Where where, String property, String column,Object obj,Object value) {
        return " or " + where.where(annotation,property, column,obj,value);
    }

    private static boolean hasAnnotation(Annotation[] annotations){
        for(Annotation annotation:annotations){
            Class annotationClass = annotation.annotationType();
            Condition condition = (Condition) annotationClass.getAnnotation(Condition.class);
            if(condition!=null) return true;
        }
        return false;
    }
    private static String getFieldHql(Object object,Field field, String propertyName,Boolean or) {
        try {
            String string = "";
            Annotation[] annotations = field.getAnnotations();

            if(!hasAnnotation(annotations)){
                Like.LikeCondition likeCondition=new Like.LikeCondition();
                string += getAndHql(null,likeCondition, propertyName, propertyName,object,String.format("%%%s%%",BeanUtil.getPropertyValue(object,propertyName)));
            }else{
                for (Annotation annotation : annotations) {
                    Class annotationClass = annotation.annotationType();
                    Condition condition = (Condition) annotationClass.getAnnotation(Condition.class);
                    if (condition != null) {
                        Class whereClass = condition.condition();
                        Constructor<Condition.Where> constructor1 = whereClass.getConstructor();
                        Condition.Where where = constructor1.newInstance();

                        Class columnClass = condition.column();
                        Constructor<Condition.Column> constructor = columnClass.getConstructor();
                        Condition.Column column = constructor.newInstance();
                        String columnName=column.column(annotation,propertyName);

                        String value=null;
                        if(condition.userValue()){
                            value=String.format(condition.format(),BeanUtil.getPropertyValue(object,propertyName));
                        }
                        if(or){
                            string += getOrHql(annotation,where, propertyName, columnName,object,value);
                        }else{
                            string += getAndHql(annotation,where, propertyName, columnName,object,value);
                        }
                    }
                }
            }
            return string;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    private static String getWhereHql(Object object) {
        String where = "";
        Class objectClass = object.getClass();
        Field[] fields = objectClass.getDeclaredFields();
        for (Field field : fields) {
            if(Modifier.isStatic(field.getModifiers())) continue;
            if(Modifier.isFinal(field.getModifiers())) continue;
            String column = field.getName();
            Object value=BeanUtil.getPropertyValue(object,column);
            if(StringUtils.isEmpty(value)) continue;
            Ignore ignore = field.getAnnotation(Ignore.class);
            if (ignore != null) continue;
            Or or = field.getAnnotation(Or.class);
            if (or != null) {
                where += " and ( 0=1 " + getFieldHql(object,field, field.getName(),true) + " )";
            } else {
                where+=getFieldHql(object,field,field.getName(),false) ;
            }
        }
        return where;
    }

    public static String parseHql(String hql,Object obj){
        Pattern pattern=Pattern.compile("like\\s(?<left>%?):(?<property>\\w*)(?<right>%?)");
        Matcher matcher=pattern.matcher(hql);
        StringBuilder string=new StringBuilder();
        int left=0;
        while (matcher.find()){
            String property=matcher.group("property");
            String leftLike=matcher.group("left");
            String rightLike=matcher.group("right");
            int start=matcher.start("left");
            int right=matcher.end("right");
            string.append(hql.substring(left,start)+"'"+leftLike+BeanUtil.getPropertyValue(obj,property)+rightLike+"'"+hql.substring(right));
            left=right;
        }
        return string.toString().equals("")?hql:string.toString();
    }
    public static String getQueryHql(Object object) {
        String hql = "from " + getClassName(object) + " where 1=1 ";
        hql += getWhereHql(object);
        return hql;
    }

    public static String getCountHql(Object object) {
        String hql = "select count(*) from " + getClassName(object) + " where 1=1 ";
        hql += getWhereHql(object);
        return hql;
    }

}
